package com.google.code.jmarias.server.tcp;

import com.google.code.jmarias.common.action.SignedAction;
import com.google.code.jmarias.common.RegisteredUser;
import com.google.code.jmarias.common.AbstractUser;
import com.google.code.jmarias.common.action.LoginAction;
import com.google.code.jmarias.common.action.SimpleSystemAction;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

/**
 *
 * @author Ondrej Michal
 */
public class JMariasServer {

    private static Log log = LogFactory.getLog(JMariasServer.class);

    /**
     * Fronta prichazejicich akci od klientu. Veskera komunikace od klientu (vlaken)
     * probiha prostrednictvim posilani zprav pres tuto frontu, proto
     * je to jediny prvek, ktery musi byt zabezpeceny proti soubeznemu pristupu. */
    private BlockingQueue<SignedAction> clientToServerActions = new LinkedBlockingQueue<SignedAction>();

    /**
     * Rozhrani, pres ktere server komunikuje s klienty. Casem muze misto jednoho rozhrani
     * byt nekolik rozhrani stejneho (jiny port) nebo jineho typu. */
    private SocketServerConnector connector = new SocketServerConnector(clientToServerActions);

    Casino casino = new Casino(clientToServerActions);

    public void start() {
        // Spusti vsechna komunikacni rozhrani.
        connector.start();

        Map<AbstractUser, ServerProtocol> onlineClients = new HashMap<AbstractUser, ServerProtocol>();

        try {
            while (true) {
                SignedAction action = clientToServerActions.take();
                AbstractContactableUser user = (AbstractContactableUser)action.getSender();


                // pokud je to akce od neznameho klienta, musi to byt uspesne prihlaseni, jinak
                // co nejrychleji zahodit
                if (action.getSender().getUsername() == null) {
                    log.debug("Prijata akce od neznameho hrace: " + action.getRawAction());
                    // @TODO pokud nejak efektivne vyresim detekci neaktivniho klienta, asi by nic nebranilo
                    // tomu, aby kontrola LoginAction byla taky v ServerProtocol

                    // @TODO kontrolovat, jestli uz stejny uzivatel neni prihlasen z jineho klienta
                    if (action.getRawAction() instanceof LoginAction) {
                        LoginAction loginAction = (LoginAction) action.getRawAction();
                        RegisteredUser p = casino.getRegisteredPlayers().get(loginAction.getUsername());
                        if (p == null) {
                            user.sendMessage(new SignedAction(new SimpleSystemAction(SimpleSystemAction.ActionType.userNotFound)));
                        } else if (!p.getPassword().equals(loginAction.getPassword())) {
                            user.sendMessage(new SignedAction(new SimpleSystemAction(SimpleSystemAction.ActionType.passwordIncorrect)));
                        } else {
                            log.debug("Uzivatel " + p + " uspesne prihlasen");
                            // uspesne prihlasen
//                            action.setAuthor(p);
                            action.getSender().setUsername(p.getUsername());
                            ServerProtocol protocol = new ServerProtocol(casino, user);
                            onlineClients.put(action.getSender(), protocol);
                            user.sendMessage(new SignedAction(new SimpleSystemAction(SimpleSystemAction.ActionType.ok)));
                        }
                    }
                } else {
                    if (log.isDebugEnabled()) {
                        log.debug("Prijata " + action);
                    }
                    if (action.getSender() instanceof BotContactableUser) {
                        Room room = ((BotContactableUser) action.getSender()).getRoom();
                        room.getCurrentGame().processAction(action);
                    } else {
                        // @TODO pouze pro testovani
                        if (! onlineClients.containsKey(action.getSender())) {
                            System.out.println("tohle by nemelo nastat, ale nevim proc");
                            onlineClients.put(action.getSender(), new ServerProtocol(casino, user));
                        }
                        ServerProtocol protocol = onlineClients.get(action.getSender());
                        protocol.processActionFromClient(action);
                    }
                }



//                if (action instanceof ConnectedClientAction) {
//                    ConnectedClientAction a = (ConnectedClientAction) action;
//                    ServerProtocol protocol = new ServerProtocol(casino, a.getClient());
//                    onlineClients.put(a.getClient(), protocol);
//                } else if (action instanceof DisconnectedClientAction) {
////                    onlineClients.remove(action.getAuthor());
//                } else {
                    
//                }
            }
        } catch (InterruptedException e) {
        }

    }

    /** Hlavni spustitelna metoda, spusti cely server. */
    public static void main(String[] args) {
        new JMariasServer().start();
    }
}
